#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "crawler_lib.h"

#define BUFF_SIZE 4096
#define FILENAME_LENGTH 1000
#define TAG_OPEN '<'
#define TAG_CLOSE '>'
#define A_HREF "href=\""
#define A_HREF_len 6
#define END_HREF '"'
//#define DEBUG

extern char text_buffer[BUFF_SIZE];
extern char link_buffer[BUFF_SIZE];
extern void FSM (char arg);
extern void reset_indexes();

int cauta_link(
char* src_buffer, char * link_buffer, enum overlap_flags * flag);
int parse_file(char * file_name, char * link_file, char * prop_file);
int insertNode(char * url, struct URLList * lista);
int readFile(char * filename, struct URLList * lista);
urlListNode * getFirstNode(struct URLList * lista);
urlListNode * getLastNode(struct URLList * lista);
void debugPrint(int node_rank, char* message);
int replaceChars(char * sir, char toReplace, char replacer);
int elimina_HTML_tags(
char* src_buffer, char* link_buffer, char* prop_buffer, enum overlap_flags * flag);
char * extrageHostDinURL(char * URL);
int parse_buffer(char* buffer, FILE * link_file, FILE * prop_file);
char * denumeste_link_file(char * url, int rank);
char * denumeste_prop_file(char * url, int rank);
char * normalizez_nume_fisier(char * nume);


/*
urlListNode * getFirstNode(struct URLList * lista)
-------------------------------------------------
Ia primul nod din lista
-------------------------------------------------
struct URLList * lista:	Lista din care sa ia primul nod
urlListNode * return: 	Primul nod din lista
*/
urlListNode * getFirstNode(struct URLList * lista)
{
	return lista;
}


/*
urlListNode * getLastNode(struct URLList * lista)
-------------------------------------------------
Ia ultimul nod din lista
-------------------------------------------------
struct URLList * lista:	Lista al carui ultim nod trebuie returnat 
urlListNode * return: 	Ultimul nod din lista
*/
urlListNode * getLastNode(struct URLList * lista)
{
	if (lista == NULL)
        	return lista;
	
	while (lista->next != NULL)
		lista = lista->next;

	return lista;
}


/*
int insertNode(char * url, struct URLList * lista)
-------------------------------------------------
Insereaza un url la sfarsitul listei
-------------------------------------------------
char* url: 		url-ul ce trebuie inserat
struct URLList* lista:	lista in care se insereaza url-ul
int return:    		0 	- succes
			!= 0 	- altfel
*/
int insertNode(char * url, struct URLList * lista)
{
	urlListNode * lastNode  = 
		(struct URLList *)malloc(sizeof(struct URLList *));
	
	
	lastNode = getLastNode(lista);

	urlListNode * Nod = 
		(struct URLList *)malloc(sizeof(struct URLList *));
	
	if (Nod == NULL)
	{
		perror("Eroare la alocarea unui nod\n");
		return errno;
	}
	
	Nod -> url = (char *)malloc(strlen(url));

	strcpy (Nod -> url, url);
	Nod -> next = NULL;
	
	
	if (lastNode -> url == NULL)
	{
		memcpy(lastNode,Nod,sizeof(struct URLList)); 
	}
	else
	{
		lastNode -> next = Nod;
	}

	return 0;
}

/*
int readFile(char * filename, struct URLList * lista)
-------------------------------------------------
Citeste url-urile din fisierul de url-uri si le 
introduce in lista.
-------------------------------------------------
char * filename: 	Numele fisierului cu url-uri
struct URLList * lista:	Lista in care sa fie introduse url-urile
int return: 		0 - succes; !=0 - altfel
*/
int readFile(char * filename, struct URLList * lista)
{
	FILE * fd;
	int urlNo, i;
	char buffer[BUFF_SIZE];

	fd = fopen(filename,"r");
	if (fd == NULL )
	{
		perror("Eroare la deschiderea fisierului\n");
		return errno;
	}
	if ( fgets(buffer, BUFF_SIZE, fd) == NULL)
	{
		perror("Eroare la citirea primei linii a fisierului\n");
		return errno;
	}
	
	urlNo = atoi(buffer);
	for ( i = 0 ; i < urlNo ; i++)
	{
		if ( fgets(buffer, BUFF_SIZE, fd) == NULL)
		{
			perror("Eroare la citirea primei linii a fisierului\n");
			return errno;
		}
		/*Daca ultimul caracter este linie noua, sfarseste stringul acolo*/
		if (buffer[strlen(buffer)-1] == '\n')
				buffer[strlen(buffer)-1] = '\0';
		insertNode(buffer, lista);
	}
	
	fclose(fd);

	return 0;
}

/*
void debugPrint(int node_rank, char* message)
-------------------------------------------------
Afiseaza informatie de debug de forma:
{0}Mesaj
Doar daca DEBUG este definit
-------------------------------------------------
int node_rank:	Rank-ul nodului
char* message:	Mesajul ce se va afisa
*/
void debugPrint(int node_rank, char* message)
{
#ifdef DEBUG
	printf("{%d}%s", node_rank, message);
#endif
	return;
}



int find_first_open_tag()
{
	return 0;
}

int find_first_close_tag()
{
	return 0;
}

/*
int cauta_link(
char* src_buffer, char * link_buffer, enum verlap_flags * flag)
-------------------------------------------------
Cauta primul url in tag-uri HTML. Parcurge intreg tag-ul HTML. Daca acesta nu se
termina in buffer-ul trimis, parcurge intreg buffer-ul.
-------------------------------------------------
int return:		pozitia din src_buffer la care s-a oprit. Oprirea
			se face la intalnirea URL_CLOSE, sau la terminarea
			buffer-ului.
char* src_buffer:	buffer-ul sursa. La intoarcere src_buffer va inainta cu
			acelasi numar de caractere cat intoarce functia.
char* link_buffer:	buffer-ul in care se copiaza link-urile intalnite
overlap_flags* flag:	indica unde am ramas
*/
int cauta_link(
char* src_buffer, char * link_buffer, enum overlap_flags * flag)
{
	char * aux = (char *)(malloc(BUFF_SIZE));
	char * local = (char *)(malloc(BUFF_SIZE));
	int ret  = 0;
	
	if (*flag == HTML)
	{
		aux = strstr(src_buffer, A_HREF);
		if ( aux == NULL)
		{
			/*
			* Nu am gasit A_HREF.
			* Verificam unde/daca se termina HTML_TAG-ul
			* si returnam
			*/
			aux = strchr(src_buffer, TAG_CLOSE);
			if (aux == NULL)
			{
				src_buffer = src_buffer + strlen(src_buffer);
				*flag = HTML;
				ret =strlen(src_buffer);
			}
			else
			{
				ret = aux - src_buffer;
				src_buffer = aux+1;
				*flag = TEXT;
				ret++ ;
			}
		}
		else
		{
			/*
			* Am gasit A_HREF. Avansam cu 6 caractere si citim adresa
			*/
			local = aux + A_HREF_len;
			aux = strchr(local, END_HREF);
			if (aux == NULL)
			{
				/*url-ul nu se termina in buffer-ul*/
				*flag = URL;
				strcpy(link_buffer, local);
				ret = strlen(src_buffer);
			}
			else
			{
				/*url-ul se termina in buffer*/
				*flag = HTML;
				strncpy(link_buffer, local, aux-local);
				ret =  aux-local;
			}
		}
	}
	return ret;
}


/*
int elimina_HTML_tags(char* src_buffer, char* dest_buffer, enum overlap_flags * flag)
-------------------------------------------------
Extrage textul dintr-un cod HTML, eliminand tag-urile de forma <tag>
-------------------------------------------------
int return:		0 - succes; !=0 - eroare
char* src_buffer:	buffer-ul sursa, ce contine codul HTML
char* link_buffer:	buffer-ul destinatie ce contine doar url-uri
char* prop_buffer:	buffer-ul destinatie ce contine doar text
short flag_overlap:	noteaza ca a ramas vreun tag anterior deschis si 
			pastreaza notatia pentru apelul viitor
*/
int elimina_HTML_tags(
char* src_buffer, char* link_buffer, char* prop_buffer, enum overlap_flags * flag)
{
	int src_buffer_len = strlen(src_buffer);
	int buffer_index = 0;
	char * aux_buffer = (char *)(malloc(BUFF_SIZE));
	
	while(buffer_index <= src_buffer_len)
	{
	
		if ( *flag == HTML )
		{
			/*
			* Ma aflu in starea 
			<html_tag .... [h]ref="...
			*/
			buffer_index = 
			cauta_link(src_buffer, link_buffer, flag);
		}
		else 
			if (*flag == URL)
			{
			/*Sunt in mijlocul unui url*/
			}
			else
			{
				/* 
				* Daca am ajuns aici pot fi intr-una din starile
				* (1) [<]html_tag ... >
				* (2) [I]n afara html_tag
				*/
				
				aux_buffer = strchr(src_buffer,TAG_OPEN);
				if (aux_buffer == NULL)
				{
					/*NU gasesc TAG_OPEN*/
					strcpy(prop_buffer, src_buffer);
					break;
				}
				buffer_index = aux_buffer - src_buffer;
				if (buffer_index == 0)
				{
					/*Daca suntem in situatia (1)*/
					buffer_index = cauta_link(
					src_buffer, link_buffer, flag);
				}
				else
				{
					/*Suntem in situatia (2)*/
					strncpy(
					prop_buffer, src_buffer, buffer_index);
					src_buffer = src_buffer + buffer_index;
				}
			
				
			}
	}
	return 0;
}
/*
int replaceChars(char * string, char toReplace, char replacer);
-------------------------------------------------
Inlocuieste fiecare aparitie in sir a literei toReplace cu replacer.
-------------------------------------------------
int return:		0 daca operatiunea a avut succes
char* sir:		sirul in care se fac schimbarile
char toReplace:	litera care va fi inlocuita
char replacer:	litera care va inlocui
*/
int replaceChars(char * sir, char toReplace, char replacer)
{
	int i = 0;
	if (sir == NULL)
		return -1;
	for ( i = 0 ; i < strlen(sir) ; i++)
		if (sir[i] == toReplace)
			sir[i] = replacer;
	return 0;
}

/*
char * extrageHostDinURL(char * URL)
-------------------------------------------------
Extrage www.ploiesti.ro din http://www.ploiesti.ro/index1.php
-------------------------------------------------
return char* : 	Host
char* URL:		URL-ul din care trebuie extras hostname-ul
*/
char * extrageHostDinURL(char * URL)
{
	char * host = (char *)malloc(FILENAME_LENGTH);
	char * aux = (char *)malloc(FILENAME_LENGTH);
	char * aux2 = (char *)malloc(FILENAME_LENGTH);
	
	int hostLength = 0;
	if (URL == NULL)	
		return NULL;
	strcpy(aux,URL);

	host = strstr(aux, "http://");
	if(host == NULL)
		return NULL;
	host = host+7;
	

	aux2 = strchr(host,'/');
	
	memset(aux2, 0, FILENAME_LENGTH);	
	
	if ( aux2 != NULL)
	{
		hostLength = aux2 - host;
		aux2 = strncpy ( aux2, host, hostLength);
	}
	else
	{
		aux2 = strcpy ( aux2, host);
	}	

	return aux2;
}


/*
OBSOLETE!!!
int parse_file(char* file_name, char* link_file, char* prop_file)
-------------------------------------------------
Parseaza fisierul file_name si pune propozitiile intalnite in prop_file
si link-urile in link_file.
-------------------------------------------------
int return: 	0 daca parsarea s-a facut cu succes, !=0 altfel
char* file_name:fisierul care va fi parsat
FILE * link_file:fisierul care va contine url-urile 
FILE * prop_file:fisierul care va contine propozitiile
*/
int parse_buffer(char* buffer, FILE * link_file, FILE * prop_file)
{

	int i = 0;	
	

	
	if (( link_file == NULL ) || ( prop_file == NULL ))
	{
		perror("Eroare la deschiderea fisierelor\n");
		return errno;
	}
	
	
	//fprintf(link_file,"[%s]\n", buffer);
	//fprintf(prop_file,"[%s]\n", buffer);

	for ( i = 0 ; i < strlen (buffer) ; i++)
		FSM(buffer[i]);


	fprintf(link_file, "\n*[%s]*\n", link_buffer);
	fprintf(prop_file, "\n*[%s]*\n", text_buffer);
	memset(text_buffer, 0 , BUFF_SIZE);
	memset(link_buffer, 0 , BUFF_SIZE);

	reset_indexes();

		
	
	return 0;
}
/*
char * denumeste_link_file(char * url, int rank);
-------------------------------------------------
Denumeste fisierul de lonk-uri pentru url-ul dat
-------------------------------------------------
char * url_file:	numele fisierului site-ului din care se vor extrage propozitiile
int rank:	rank-ul nodului care parcurge site-ul
return char*:	numele fisierului
*/
char * denumeste_link_file(char * url_file, int rank)
{
	char * file = (char *)malloc(FILENAME_LENGTH);
	memset(file, 0 , FILENAME_LENGTH);
	sprintf(file,"%s_link_file-%d.txt",url_file, rank);
	return file;
	
}


/*
char * denumeste_prop_file(char * url, int rank);
-------------------------------------------------
Denumeste fisierul de propozitii / text pentru url-ul dat
-------------------------------------------------
char * url_file:	numele fisierului site-ului din care se vor extrage propozitiile
int rank:	rank-ul nodului care parcurge site-ul
return char*:	numele fisierului
*/
char * denumeste_prop_file(char * url_file, int rank)
{
	char *  file = (char *)malloc(FILENAME_LENGTH);
	memset(file, 0 , FILENAME_LENGTH);
	sprintf(file,"%s_prop_file-%d.txt",url_file, rank);
	return file;
	
}

/*
char * normalizez_nume_fisier(char * nume);
-------------------------------------------------
Elimina din nume caracterele care nu pot aparea intr-un nume de fisier
-------------------------------------------------
char * nume:	numele din care trebuie eliminate caracterele speciale
return char *:	numele normalizat
*/
char * normalizez_nume_fisier(char * nume)
{
	char *  file = (char *)malloc(FILENAME_LENGTH);
	strcpy(file, nume);
	replaceChars(file,'/','_');
	replaceChars(file,':','_');
	return file;

}
